import { Col, Form, Row } from 'antd'
import { isValidElement, Suspense } from 'react'

import getComponent from './getComponent'
import { transformFromItem } from './transformItem'
import ViewFormItem from './ViewFormItem'

const getCol = ({ col, width, style: itemStyle }, totalCol) => {
  if (width) {
    return {
      style: {
        float: 'left',
        verticalAlign: 'top',
        display: 'inline-block',
        ...itemStyle,
        width,
      },
    }
  }
  if (typeof col === 'number') {
    return { span: col }
  } else if (Array.isArray(col)) {
    return { sm: col[0], xs: col[0], md: col[0], lg: col[1], xl: col[2], xxl: col[3] }
  }
  if (typeof totalCol === 'number') {
    return { span: totalCol }
  }
  return { span: 24 }
}

const getLayout = (layout, totalLayout) => {
  layout = layout || totalLayout || ['100px'] // [6, 18]
  const format = (key, value) => {
    if (value) {
      if (typeof value === 'number') {
        return { [key]: { span: value } }
      }
      return { [key]: value }
    }
    return { label: undefined }
  }
  if (Array.isArray(layout) && layout[0]?.includes?.('px')) {
    return {
      labelCol: { flex: layout[0] },
      wrapperCol: { flex: layout[1] || '1' },
    }
  }
  if (Array.isArray(layout) && layout.length === 2) {
    return {
      ...format('labelCol', layout[0]),
      ...format('wrapperCol', layout[1]),
    }
  }
  return layout
}

/**
 * @typedef {Omit<import('rc-picker/lib/PickerPanel').PickerPanelProps<DateType>, ''>} DatePickerProps
 */

/**
 * @typedef {Object} ExtraComponentPropsProps
 * @property {number | string} [width] 组件宽度
 */

/**
 * @typedef { import("react").CSSProperties &
 * import("antd/es/auto-complete").AutoCompleteProps &
 * import("antd/es/input").InputProps &
 * import("antd/es/input/Search").SearchProps &
 * import("antd/es/input/Password").PasswordProps &
 * import("antd/es/input/Group").GroupProps &
 * import("antd/es/input/TextArea").TextAreaProps &
 * import("antd/es/input-number").InputNumberProps &
 * import("antd/es/switch").SwitchProps &
 * import("antd/es/radio").RadioProps &
 * import("antd/es/radio").RadioGroupProps &
 * import("antd/es/checkbox").CheckboxProps &
 * import("antd/es/checkbox").CheckboxGroupProps &
 * import("antd/es/time-picker").TimePickerProps &
 * import("antd/es/date-picker").DatePickerProps &
 * import("antd/es/date-picker").RangePickerProps &
 * import("antd/es/cascader").CascaderProps &
 * import("antd/es/select").SelectProps &
 * import("antd/es/tree-select").TreeSelectProps &
 * import("antd/es/tree").TreeProps &
 * import("../AekSelect").AekSelectProps &
 * import("../AekTreeSelect").AekTreeSelectProps &
 * import("../AekUpload").AekUploadProps &
 * import("../AekTextArea").AekTextAreaProps &
 * import("../AekCascader").AekCascaderProps &
 * ExtraComponentPropsProps
 * } ComponentPropsProps
 */

/**
 * @typedef {Object} ComponentProps
 * @property {import("./getComponent").ComponentNameProps} [name] 组件名或者组件
 * @property {ComponentPropsProps} [props] 组件属性
 */

/**
 * @typedef {Object} FormDataProps
 * @property {string | string[]} [field] 字段名
 * @property {string} [label] 描述
 * @property {number} [col] 整行占比，24为一行
 * @property {number[]} [layout] [label, Comp]，默认['100px']
 * @property {boolean} [exclude] 是否不加载
 * @property {import("antd/es/form").FormItemProps} [formItemProps] 配置项
 * @property {import("react").CSSProperties} [style] 组件样式
 * @property {ComponentProps | FormDataProps[]} [component] 组件
 * @property {React.ReactNode} [other] 额外的组件
 * @property {boolean} [view] 是否作为展示组件，若AekForm设置了allView=true，则一律作为展示组件
 * @property {string | string[]} [viewField] 默认用field，若配置了viewField，用viewField
 * @property {(value: any, detail: Object) => React.ReactNode} [viewRender] 当作为展示组件时返回
 * // 以下属性只作为展示组件时使用
 * @property {boolean} [isDate] 日期YYYY-MM-DD
 * @property {boolean} [isDateTime] 时间YYYY-MM-DD HH:mm:ss
 * @property {boolean} [isMoney] 钱
 * @property {import("@/utils/enum").default} [enum] 枚举
 */

/**
 * @typedef {Object} OtherAekFormProps
 * @property {number} [col] 整行占比，24为一行
 * @property {number[]} [layout] [label, Comp]，默认['100px']
 * @property {FormDataProps[]} [formData] 表单配置
 * @property {boolean} [allView] 是否作为展示组件
 * @property {{}} [detail] 当作为展示组件时，需要传入详情数据
 * @property {(form) => {}} [getForm] 返回form实例
 * @property {number} [gutter]
 */

/**
 * @typedef {import("antd/es/form").FormProps & OtherAekFormProps} AekFormProps
 */

/**
 * @param {AekFormProps} props
 * @returns
 */
const AekForm = props => {
  /**
   * @type {AekFormProps}
   */
  const {
    col: totalCol,
    layout: totalLayout,
    formData,
    allView = false,
    detail = {},
    gutter = 20,
    ...otherProps
  } = props

  const [form] = AekForm.useForm()

  const getItem = fmData => {
    const formItemArr = []
    fmData.forEach((itm, index) => {
      if (isValidElement(itm)) {
        formItemArr.push(
          <div style={{ clear: 'both' }} key={itm.key || index}>
            {itm}
          </div>,
        )
      } else if (itm && !itm.exclude) {
        /** @type {FormDataProps} */
        const item = transformFromItem(itm, allView)
        const baseProps = {
          label: item.label,
          ...getLayout(item.layout, totalLayout),
        }
        const key = item.key || item.field || index
        const formItem = (
          <Col
            id={item.field}
            className={item.className}
            style={{ verticalAlign: 'top', display: 'inline-block', wordBreak: 'break-all', ...item.style }}
            {...getCol(item, totalCol)}
            key={key}
          >
            {!allView && !item.view ? (
              // getComponent里用了React.lazy，所以这里要包裹一层
              <Suspense>
                {item.other ? (
                  <Form.Item {...baseProps} required={item.formItemProps?.rules?.find(({ required }) => required)}>
                    <div style={{ display: 'flex' }}>
                      <Form.Item
                        className='mb0'
                        style={{
                          width: item.component?.props?.width,
                          flex: item.component?.props?.width ? 'unset' : 1,
                        }}
                        {...{ name: item.field, ...item.formItemProps }}
                      >
                        {getComponent(item.component, key)}
                      </Form.Item>
                      <Form.Item className='ml10px mb0 whitespace-nowrap'>{item.other}</Form.Item>
                    </div>
                  </Form.Item>
                ) : (
                  <Form.Item {...baseProps} {...{ name: item.field, ...item.formItemProps }}>
                    {getComponent(item.component, key)}
                  </Form.Item>
                )}
              </Suspense>
            ) : (
              <ViewFormItem {...baseProps} detail={detail} item={item} />
            )}
          </Col>
        )
        formItemArr.push(formItem)
      }
    })
    return formItemArr
  }
  return (
    <Form form={form} {...otherProps}>
      <Row gutter={gutter} style={{ overflow: 'hidden', verticalAlign: 'top' }} type='flex' align='top'>
        {getItem(formData)}
      </Row>
    </Form>
  )
}

AekForm.useForm = Form.useForm
AekForm.useWatch = Form.useWatch
AekForm.Item = Form.Item
export default AekForm
